summaryrefslogtreecommitdiffstats
path: root/src/net/gcdc/asn1/uper/BitStringCoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/gcdc/asn1/uper/BitStringCoder.java')
-rw-r--r--src/net/gcdc/asn1/uper/BitStringCoder.java165
1 files changed, 165 insertions, 0 deletions
diff --git a/src/net/gcdc/asn1/uper/BitStringCoder.java b/src/net/gcdc/asn1/uper/BitStringCoder.java
new file mode 100644
index 0000000..e60c68e
--- /dev/null
+++ b/src/net/gcdc/asn1/uper/BitStringCoder.java
@@ -0,0 +1,165 @@
+package net.gcdc.asn1.uper;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import net.gcdc.asn1.datatypes.Asn1VarSizeBitstring;
+import net.gcdc.asn1.datatypes.Bitstring;
+import net.gcdc.asn1.datatypes.FixedSize;
+import net.gcdc.asn1.datatypes.SizeRange;
+import net.gcdc.asn1.uper.UperEncoder.Asn1ContainerFieldSorter;
+
+class BitStringCoder implements Decoder, Encoder {
+
+ @Override public <T> boolean canEncode(T obj, Annotation[] extraAnnotations) {
+ Class<?> type = obj.getClass();
+ AnnotationStore annotations = new AnnotationStore(type.getAnnotations(),
+ extraAnnotations);
+ return annotations.getAnnotation(Bitstring.class) != null;
+ }
+
+ @Override public <T> void encode(BitBuffer bitbuffer, T obj, Annotation[] extraAnnotations) throws Asn1EncodingException {
+ Class<?> type = obj.getClass();
+ AnnotationStore annotations = new AnnotationStore(type.getAnnotations(),
+ extraAnnotations);
+ if (!(obj instanceof Asn1VarSizeBitstring)) {
+ if (UperEncoder.hasExtensionMarker(annotations)) {
+ throw new UnsupportedOperationException(
+ "Bitstring with extensions is not implemented yet");
+ }
+ FixedSize size = type.getAnnotation(FixedSize.class);
+ int position = bitbuffer.position();
+ if (size != null) {
+ Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(type);
+ if (sorter.ordinaryFields.size() != size.value()) { throw new AssertionError(
+ "Declared size (" + size.value() +
+ ") and number of fields (" + sorter.ordinaryFields.size() +
+ ") do not match!"); }
+ for (Field f : sorter.ordinaryFields) {
+ try {
+ bitbuffer.put(f.getBoolean(obj));
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalArgumentException("can't encode" + obj, e);
+ }
+ }
+ UperEncoder.logger.debug(String.format("BITSTRING %s, encoded as <%s>", obj.getClass().getName(),
+ bitbuffer.toBooleanStringFromPosition(position)));
+ return;
+ } else {
+ throw new UnsupportedOperationException(
+ "Bitstrings of variable size are not implemented yet");
+ }
+ } else if (obj instanceof Asn1VarSizeBitstring) {
+ int position = bitbuffer.position();
+ if (UperEncoder.hasExtensionMarker(annotations)) { throw new UnsupportedOperationException(
+ "Bitstring with extensions is not implemented yet"); }
+ Asn1VarSizeBitstring bitstring = (Asn1VarSizeBitstring) obj;
+ FixedSize fixedSize = annotations.getAnnotation(FixedSize.class);
+ SizeRange sizeRange = annotations.getAnnotation(SizeRange.class);
+ if (fixedSize != null) {
+ for (int i = 0; i < fixedSize.value(); i++) {
+ bitbuffer.put(bitstring.getBit(i));
+ }
+ UperEncoder.logger.debug(String.format("BITSTRING %s: %s", obj.getClass().getName(),
+ bitbuffer.toBooleanStringFromPosition(position)));
+ return;
+ } else if (sizeRange != null) {
+ int position1 = bitbuffer.position();
+ UperEncoder.encodeConstrainedInt(bitbuffer, bitstring.size(), sizeRange.minValue(),
+ sizeRange.maxValue());
+ int position2 = bitbuffer.position();
+ for (int i = 0; i < bitstring.size(); i++) {
+ bitbuffer.put(bitstring.getBit(i));
+ }
+ UperEncoder.logger.debug(String.format("BITSTRING %s size %s: %S", obj.getClass().getName(),
+ bitbuffer.toBooleanString(position1, position2 - position1),
+ bitbuffer.toBooleanStringFromPosition(position2)));
+ return;
+ } else {
+ throw new IllegalArgumentException("Both SizeRange and FixedSize are null");
+ }
+ }
+ }
+
+ @Override public <T> boolean canDecode(Class<T> classOfT, Annotation[] extraAnnotations) {
+ AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),
+ extraAnnotations);
+ return annotations.getAnnotation(Bitstring.class) != null;
+ }
+
+ @Override public <T> T decode(BitBuffer bitbuffer,
+ Class<T> classOfT, Field field,
+ Annotation[] extraAnnotations) {
+ AnnotationStore annotations = new AnnotationStore(classOfT.getAnnotations(),
+ extraAnnotations);
+ if (!Asn1VarSizeBitstring.class.isAssignableFrom(classOfT)) {
+ UperEncoder.logger.debug("Bitlist(fixed-size, all-named)");
+ FixedSize fixedSize = annotations.getAnnotation(FixedSize.class);
+ if (fixedSize == null) { throw new UnsupportedOperationException(
+ "bitstrings of non-fixed size that do not extend Asn1VarSizeBitstring are not supported yet");
+ }
+ Asn1ContainerFieldSorter sorter = new Asn1ContainerFieldSorter(classOfT);
+ if (fixedSize.value() != sorter.ordinaryFields.size()) { throw new IllegalArgumentException(
+ "Fixed size annotation " + fixedSize.value()
+ + " does not match the number of fields "
+ + sorter.ordinaryFields.size() + " in " + classOfT.getName()); }
+ if (UperEncoder.hasExtensionMarker(annotations)) {
+ boolean extensionPresent = bitbuffer.get();
+ if (extensionPresent) { throw new UnsupportedOperationException(
+ "extensions in fixed-size bitlist are not supported yet"); }
+ }
+ T result = UperEncoder.instantiate(classOfT);
+ for (Field f : sorter.ordinaryFields) {
+ boolean value = bitbuffer.get();
+ UperEncoder.logger.debug(String.format("Field %s set to %s", f.getName(), value));
+ try {
+ f.set(result, value);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new IllegalArgumentException("can't decode " + classOfT, e);
+ }
+ }
+ return result;
+ } else {
+ UperEncoder.logger.debug("Bitlist(var-size)");
+ FixedSize fixedSize = annotations.getAnnotation(FixedSize.class);
+ SizeRange sizeRange = annotations.getAnnotation(SizeRange.class);
+ // We use reflection here to access protected method of Asn1VarSizeBitstring.
+ // Alternative would be to mandate BitSet constructors for all subclasses of
+ // Asn1VarSizeBitstring.
+ Method setBitMethod;
+ try {
+ setBitMethod = Asn1VarSizeBitstring.class.getDeclaredMethod("setBit", int.class,
+ boolean.class);
+ setBitMethod.setAccessible(true);
+ } catch (SecurityException | NoSuchMethodException e) {
+ throw new AssertionError("Can't find/access setBit " + e);
+ }
+ Long size = (fixedSize != null) ? fixedSize.value() :
+ (sizeRange != null) ? UperEncoder.decodeConstrainedInt(bitbuffer,
+ UperEncoder.intRangeFromSizeRange(sizeRange)) :
+ badSize(classOfT);
+ T result = UperEncoder.instantiate(classOfT);
+ for (int i = 0; i < size; i++) {
+ try {
+ setBitMethod.invoke(result, i, bitbuffer.get());
+ } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
+ throw new IllegalArgumentException("Can't invoke setBit", e);
+ }
+ }
+ return result;
+ }
+ }
+
+ /** This function only throws an exception, to be used in ternary (a?b:c) expression. */
+ static <T> Long badSize(Class<T> classOfT) {
+ throw new IllegalArgumentException("both size range and fixed size are null for "
+ + classOfT.getName());
+ }
+
+ @Override
+ public <T> T getDefault(Class<T> classOfT, Annotation[] extraAnnotations) {
+ throw new IllegalArgumentException("Default Sequence not yet implemented");
+ }
+} \ No newline at end of file